package org.pblue.tumblarity.task;

import java.io.IOException;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.pblue.appengine.AppengineDataManager;
import org.pblue.tumblarity.data.bean.Tumblelog;
import org.pblue.tumblarity.service.FetchAllService;
import org.pblue.tumblarity.tools.TumblrHttpTools;

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;

/**
 * This is a fetchtumblelog-queue task mapped to /task/fetchtumblelog. It has the following
 * parameters:
 * 
 * tumblelogId (required): the tumblelog id to be fetched.
 * 
 * @author mikolaj
 *
 */
public class FetchTumblelog extends HttpServlet {

  private static final long serialVersionUID = 1L;
  
  private static final Logger log = Logger.getLogger(FetchTumblelog.class.getName());

  @Override
  protected void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
    Queue fetchPageQueue = QueueFactory.getQueue(FetchAllService.QUEUE_FETCH_PAGE);
    
    String tumblelogId = pRequest.getParameter(FetchAllService.PARAM_TUMBLELOG_ID);
    
    // retrieve tumblelog object from the datastore
    AppengineDataManager dataManager = AppengineDataManager.open();
    
    try {
      dataManager.begin();
      Tumblelog tumblelog = Tumblelog.get(tumblelogId,dataManager);

      if (tumblelog != null) {
        
        // check if tumblelog's fetch state is idle
        if (tumblelog.getFetchState() == Tumblelog.FETCH_STATE_IDLE) {
          
          boolean exists = TumblrHttpTools.tumblelogExists(tumblelog.getEmail(), tumblelog.getTumblelog(), tumblelog.getPassword());

          if (exists) {
            log.info("Processing tumblelog " + tumblelogId + ".");

            // set the tumblelog's fetch state to 'processing' and the last fetched date to now
            tumblelog.setFetchState(Tumblelog.FETCH_STATE_PROCESSING);

            tumblelog.save(dataManager);
            dataManager.commit();

            // queue a task for the first page of the tumblelog to fetch that page
            fetchPageQueue.add(TaskOptions.Builder.withUrl("/task/fetchpage")
                .param(FetchAllService.PARAM_TUMBLELOG_ID, tumblelogId)
                .param(FetchAllService.PARAM_PAGE, "1")
            );

          } else {
            log.warning("Tumblelog " + tumblelogId + " not found.");

            tumblelog.setFetchState(Tumblelog.FETCH_STATE_ERROR);
            tumblelog.setLastFetched(new Date());

            tumblelog.save(dataManager);
            dataManager.commit();
          }

        } else if (tumblelog.getFetchState() == Tumblelog.FETCH_STATE_PROCESSING) {
          log.warning("Tumblelog " + tumblelogId + " is already being fetched, not processing.");
        
        } else if (tumblelog.getFetchState() == Tumblelog.FETCH_STATE_ERROR) {
          
          if (tumblelog.getFetchRetryCount() <= Tumblelog.MAX_FETCH_RETRY) {
            boolean exists = TumblrHttpTools.tumblelogExists(tumblelog.getEmail(), tumblelog.getTumblelog(), tumblelog.getPassword());
            tumblelog.setFetchRetryCount(tumblelog.getFetchRetryCount() + 1);

            if (exists) {
              log.info("Tumblelog " + tumblelogId + " found, setting fetch state to IDLE, will be fetched next time.");
              tumblelog.setFetchState(Tumblelog.FETCH_STATE_IDLE);
              tumblelog.setFetchRetryCount(0);
              tumblelog.setLastFetched(new Date());
            }

            tumblelog.save(dataManager);
            dataManager.commit();
            
          } else {
            tumblelog.remove(dataManager);
            dataManager.commit();
            log.warning("Tumblelog " + tumblelogId + " has failed to fetch too many times, deleting tumblelog.");
          }
          
        }
        
      } else {
        log.severe("Couldn't retrieve tumbelog with id " + tumblelogId + ".");
      }

    } catch (Exception e) {
      log.log(Level.SEVERE, "Couldn't process tumbelog with id " + tumblelogId + ".", e);
    } finally {
      dataManager.rollback();
      dataManager.close();
    }
  }

}
